package cn.tedu.tmall.passport.service.impl;

import cn.tedu.common.enumerator.ServiceCode;
import cn.tedu.common.ex.ServiceException;
import cn.tedu.common.pojo.authentication.CurrentPrincipal;
import cn.tedu.common.pojo.po.UserStatePO;
import cn.tedu.tmall.passport.dao.cache.IUserCacheRepository;
import cn.tedu.tmall.passport.dao.persist.repository.IUserRepository;
import cn.tedu.tmall.passport.pojo.entity.User;
import cn.tedu.tmall.passport.pojo.param.LoginByPhoneParam;
import cn.tedu.tmall.passport.pojo.param.UserLoginInfoParam;
import cn.tedu.tmall.passport.pojo.param.UserRegParam;
import cn.tedu.tmall.passport.pojo.vo.LoginRegVO;
import cn.tedu.tmall.passport.pojo.vo.UserLoginInfoVO;
import cn.tedu.tmall.passport.pojo.vo.UserLoginResultVO;
import cn.tedu.tmall.passport.service.HttpUtils;
import cn.tedu.tmall.passport.service.IUserService;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;
@Slf4j
@Service
public class UserServiceImpl implements IUserService {

    @Value("${tmall.jwt.secret-key}")
    private   String secretKey;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private IUserRepository userRepository;
    @Autowired
    private IUserCacheRepository userCacheRepository;



    @Autowired
    PasswordEncoder encoder;

    //用户注册
    @Override
    public int userReg(UserRegParam userRegParam) {
        String phone = userRegParam.getPhone();
//        LoginInfoVO infoByPhone = userRepository.getInfoByPhone(phone);
        /*根据名字查看用户是否存在*/
        UserLoginInfoVO userInfo = userRepository.getLoginInfoByUsername(userRegParam.getUsername());
        if(userInfo!=null){
            String message ="用户名已存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_UNKNOWN,message);
        }
        /*注册用户*/
        User user = new User();

        user.setEnable(1);
//        user.setRole(1L);
        BeanUtils.copyProperties(userRegParam,user);
//        user.setAvatar("/img/defaultAvatar.png");
        user.setPassword(encoder.encode(userRegParam.getPassword()));
        return userRepository.userReg(user);

    }


    @Override
    public UserLoginResultVO login(UserLoginInfoParam userLoginInfoParam, String remoteAddr, String userAgent) {
        String username = userLoginInfoParam.getUsername();
        UserLoginInfoVO loginInfo = userRepository.getLoginInfoByUsername(username);
        if (loginInfo == null) {
            String message = "登录失败，用户名或密码错误！";
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED, message);
        }

        if (loginInfo.getEnable() != 1) {
            String message = "登录失败，此账号已经被禁用！";
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED_DISABLED, message);
        }

        String password = userLoginInfoParam.getPassword();
        // if (!loginInfo.getPassword().equals(password)) {
        if (!passwordEncoder.matches(password, loginInfo.getPassword())) {
            String message = "登录失败，用户名或密码错误！";
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED, message);
        }

        // TODO 处理登录日志相关：向登录日志表中插入数据，修改用户表中冗余存储的登录数据

        // 确定当事人
        CurrentPrincipal principal = new CurrentPrincipal();
        principal.setId(loginInfo.getId());
        principal.setUsername(loginInfo.getUsername());
        principal.setNickname(loginInfo.getNickname());
        principal.setEmail(loginInfo.getEmail());
        principal.setPhone(loginInfo.getPhone());
        principal.setCardNumber(loginInfo.getCardNumber());


        // 确定权限列表
        List<GrantedAuthority> authorities = new ArrayList<>();
        List<String> permissions = loginInfo.getPermissions();
        for (String permission : permissions) {
            authorities.add(new SimpleGrantedAuthority(permission));
        }

        // 将权限列表和用户状态写入到Redis中
        String authoritiesJsonString = JSON.toJSONString(authorities);
        UserStatePO userStatePO = new UserStatePO();
        userStatePO.setEnable(loginInfo.getEnable());
        userStatePO.setAuthoritiesJsonString(authoritiesJsonString);
        userCacheRepository.saveUserState(loginInfo.getId(), userStatePO);

        // 向SecurityContext中存入Authentication
        // Authentication authentication = new UsernamePasswordAuthenticationToken(
        //        principal, null, authorities);
        // SecurityContext securityContext = SecurityContextHolder.getContext();
        // securityContext.setAuthentication(authentication);

        Map<String, Object> claims = new HashMap<>();
        claims.put("id", loginInfo.getId());
        claims.put("username", loginInfo.getUsername());
        claims.put("nickname", loginInfo.getNickname());
        claims.put("email", loginInfo.getEmail());
        claims.put("phone", loginInfo.getPhone());
        claims.put("cardNumber", loginInfo.getCardNumber());
        claims.put("remote_addr", remoteAddr);
        claims.put("user_agent", userAgent);

        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // Payload
                .setClaims(claims)
                // Verify Signature
                .signWith(SignatureAlgorithm.HS256, secretKey)
                // 完成
                .compact();

        UserLoginResultVO loginResult = new UserLoginResultVO();
        loginResult.setId(loginInfo.getId());
        loginResult.setUsername(loginInfo.getUsername());
        loginResult.setNickname(loginInfo.getNickname());
        loginResult.setEmail(loginInfo.getEmail());
        loginResult.setPhone(loginInfo.getPhone());
        loginResult.setCardNumber(loginInfo.getCardNumber());
        loginResult.setAvatar(loginInfo.getImgeUrl());
        loginResult.setToken(jwt);
        loginResult.setAuthorities(permissions);
        return loginResult;
    }

    @Override
    public void logout(CurrentPrincipal currentPrincipal) {
        Long id = currentPrincipal.getId();
        userCacheRepository.deleteUserState(id);
    }




    @Override
    public void sendMessage(String phone) {
        //短信api调用地址
        String host = "https://dfsns.market.alicloudapi.com";
        //请求路径
        String path = "/data/send_sms";
        //请求方式
        String method = "POST";
        //appcode：自己的AppCode，可以在自己的控制台找到，是一串32位的字符串
        String appcode = "cf14a73856b54c4a84fcb866f5991690";
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);
        //根据API的要求，定义相对应的Content-Type
        headers.put("Con" +
                "+tent-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        Map<String, String> querys = new HashMap<String, String>();
        Map<String, String> bodys = new HashMap<String, String>();

        //使用随机数生成4位验证码
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            int randomNum = (int) (Math.random()*10);
            stringBuilder.append(randomNum);
        }
        String code = stringBuilder.toString();
        System.out.println(code);
        // 将code存入redis
        userCacheRepository.saveCode(phone, code);
        // TODO 将code存入redis
        //这里是要发送给用户的验证码，我们使用了随机数进行生成
        bodys.put("content", "code:"+code);
        //这里是接受短信的手机号码，我们在实际开发时这里就不能写死了
        bodys.put("phone_number", phone);
        //这里是发送短信的模板ID：代表整体短信文案模板
        bodys.put("template_id", "TPL_0000");
        try {
            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            System.out.println(response.toString());
            //获取response的body
            System.out.println(EntityUtils.toString(response.getEntity()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public UserLoginResultVO loginByPhone(
            LoginByPhoneParam loginByPhoneParam,
            String remoteAddr , String userAgent) {


        String phone = loginByPhoneParam.getPhone();


        UserLoginInfoVO loginInfo = userRepository.getLoginInfoByPhone(phone);


        if (loginInfo == null) {
            String message = "登录失败，手机号错误！";
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED, message);
        }

        if (loginInfo.getEnable() != 1) {
            String message = "登录失败，此账号已经被禁用！";
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED_DISABLED, message);
        }



        String code = loginByPhoneParam.getCode();


        // 从redis中取出code
        String redisCode = userCacheRepository.getCode(phone);
//         if (!loginInfo.getPassword().equals(password)) {
        if (!code.equals(redisCode)) {
            String message = "登录失败，验证码错误或验证码已失效，请重新获取验证码！";
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED, message);
        }

        // 删除redis中的code
       // userCacheRepository.deleteCode(phone);



        // 确定当事人
        CurrentPrincipal principal = new CurrentPrincipal();

        principal.setId(loginInfo.getId());
        principal.setUsername(loginInfo.getUsername());

        log.info("++++++++++++++++++++"+principal);

        // 确定权限列表
//        List<GrantedAuthority> authorities = new ArrayList<>();
//        List<String> permissions = loginInfo.getPermissions();
//
//        log.info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"+permissions);
//        log.info("+++++++++++++++++++++++++++++++++++++++++++++++"+loginInfo.getPermissions().toString());
//
//        if (permissions.size()==0){
//            permissions.add("1");
//        }
//        for (String permission : permissions) {
//            authorities.add(new SimpleGrantedAuthority(permission));
//        }

        // 将权限列表和用户状态写入到Redis中
        String authoritiesJsonString = JSON.toJSONString(null);
        UserStatePO userStatePO = new UserStatePO();
        userStatePO.setEnable(loginInfo.getEnable());
        userStatePO.setAuthoritiesJsonString(authoritiesJsonString);
        userCacheRepository.saveUserState(loginInfo.getId(), userStatePO);

        // 向SecurityContext中存入Authentication
         Authentication authentication = new UsernamePasswordAuthenticationToken(
                principal, null, null);
         SecurityContext securityContext = SecurityContextHolder.getContext();
         securityContext.setAuthentication(authentication);

        Map<String, Object> claims = new HashMap<>();
        claims.put("id", loginInfo.getId());
        claims.put("username", loginInfo.getUsername());
        claims.put("remote_addr", remoteAddr);
        claims.put("user_agent", userAgent);

        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // Payload
                .setClaims(claims)
                // Verify Signature
                .signWith(SignatureAlgorithm.HS256, secretKey)
                // 完成
                .compact();

        UserLoginResultVO loginResult = new UserLoginResultVO();
        loginResult.setId(loginInfo.getId());
        loginResult.setUsername(loginInfo.getUsername());
        loginResult.setAvatar(loginInfo.getImgeUrl());
        loginResult.setToken(jwt);
        loginResult.setAuthorities(null);
        return loginResult;
    }


    }
